package com.dbh.alg.algorithm.hot100.二叉树;

import com.dbh.alg.algorithm.hot100.TreeNode;

import java.util.HashMap;
import java.util.Map;

/**
 * 给定一个二叉树的根节点 root ，和一个整数 targetSum ，求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
 *
 * 路径 不需要从根节点开始，也不需要在叶子节点结束，但是路径方向必须是向下的（只能从父节点到子节点）。
 */
public class Leetcode437_路径总和2 {

    public int pathSum(TreeNode root, int targetSum) {
        // 创建前缀和、和映射表：key-前缀和，value-该前缀和出现的次数
        Map<Long, Integer> prefix = new HashMap<>();
        // 初始化：前缀和为0出现1次（空路径）
        prefix.put(0L, 1);
        // 深度优先搜索计算路径数量
        return dfs(root, prefix, 0L, targetSum);
    }

    private int dfs(TreeNode root, Map<Long, Integer> prefix, Long curr, int targetSum) {
        // 空节点返回0
        if (root == null) {
            return 0;
        }
        // 当前子树中满足条件的路径数
        int ret = 0;
        // 更新当前路径的前缀和
        curr += root.val;

        // 核心逻辑：检查是否存在当前前缀和满足curr - prefixSum = targetSum
        // 即prefixSum = curr - targetSum
        ret = prefix.getOrDefault(curr - targetSum, 0);

        // 将当前前缀和加入映射表（用于后续节点查找）
        prefix.put(curr, prefix.getOrDefault(curr, 0) + 1);

        // 递归计算左右子树中的路径数
        ret += dfs(root.left, prefix, curr, targetSum);
        ret += dfs(root.right, prefix, curr, targetSum);

        // 回溯：将当前前缀和从映射表中移除(恢复状态，避免影响其他分支)
        prefix.put(curr, prefix.getOrDefault(curr,  0) - 1);

        return ret;
    }
}
